﻿package com.cilico.components;

import java.util.HashMap;
import java.util.Vector;

import com.cilico.utils.Utils;

/**
 * CSS样式
 * @author lv.xiangan
 *
 */

public class CssStyle {
	static int NODE = 0;
	static int CLASS = 1;
	static int BORDER_LEFT = 0;
	static int BORDER_TOP = 1;
	static int BORDER_RIGHT = 2;
	static int BORDER_BOTTOM = 3;
	public int top_ = Integer.MIN_VALUE;
	public int left_ = Integer.MIN_VALUE;
	public int bottom_ = Integer.MIN_VALUE;
	public int right_ = Integer.MIN_VALUE;
	public int width_ = -1;
	public int height_ = -1;
	int fgColor_ = 0;
	public int bgColor_ = 0;
	public String bgImageUrl_ = null;
	int borderWidth_ = -1;
	int borderColor_ = 0;
	int[] borderWidths_;
	int[] borderColors_;
	int fontSize_ = -1;
	String fontFamily_ = null;
	String fontWeight_ = null;
	String textAlign_ = null; // 对齐方式：left/right/center
	public String display_ = null; //模块显示： none/block
	// 删除线粗细
	public int strikethrough_ = -1;

	/**
	 * @param styleStr
	 * @return
	 */
	static final Vector<HashMap<String, CssStyle>> parseStyle(String styleStr) {
		if (styleStr == null || styleStr.trim().equals("")) {
			return null;
		}

		Vector<HashMap<String, CssStyle>> vec = new Vector<HashMap<String, CssStyle>>(2);
		HashMap<String, CssStyle> nodeStyles = new HashMap<String, CssStyle>();
		HashMap<String, CssStyle> classStyles = new HashMap<String, CssStyle>();
		vec.add(nodeStyles);
		vec.add(classStyles);

		// divide the string to style strings, e.g., "xxx{xxx}".
		String[] sepedStr = Utils.string2Array(styleStr, "}");
		if (sepedStr == null) {
			return null;
		}

		// dispose each style string.
		int arrStrSize = sepedStr.length;
		for (int i = 0; i < arrStrSize; i++) {
			String[] styleArr = Utils.string2Array(sepedStr[i], "{");
			if (styleArr.length != 2) {
				// the array must consist of 2 elements: CSS selector string and
				// value string.
				continue;
			}

			// dispose CSS selectors.
			String[] selectors = Utils.string2Array(styleArr[0], ",");
			if (selectors == null) {
				continue;
			}

			// dispose values.
			CssStyle style = createStyle(styleArr[1]);
			if (style == null) {
				continue;
			}

			// restore styles.
			int selSize = selectors.length;
			for (int j = 0; j < selSize; j++) {
				selectors[j] = selectors[j].trim();
				if (selectors[j].startsWith(".")) {
					// delete the '.' at the front of the class name. e.g.,
					// .name.
					selectors[j] = selectors[j].substring(1);
					classStyles.put(selectors[j], style);
				} else {
					nodeStyles.put(selectors[j], style);
				}
			}
		}

		return vec;
	}

	/**
	 * @param propertyStr
	 * @return
	 */
	private static final CssStyle createStyle(String propertyStr) {
		if (propertyStr == null || propertyStr.trim().equals("")) {
			return null;
		}

		String[] propertyArr = Utils.string2Array(propertyStr, ";");
		if (propertyArr == null) {
			return null;
		}

		CssStyle cstyle = new CssStyle();

		// dispose each style value.
		int propertyNum = propertyArr.length;
		String propertyName;
		String propertyValue;
		for (int i = 0; i < propertyNum; i++) {
			propertyName = null;
			propertyValue = null;
			int sepIndex = propertyArr[i].indexOf(':');
			if (sepIndex == -1) {
				continue;
			}

			try {
				propertyName = propertyArr[i].substring(0, sepIndex).trim();
				propertyValue = propertyArr[i].substring(sepIndex + 1).trim();
			} catch (Exception e1) {
				continue;
			}

			if (propertyName == null || propertyName.equals("")) {
				continue;
			}

			try {
				if (propertyName.equalsIgnoreCase("width")) {
					// e.g., 80px
					cstyle.width_ = Utils.getScaledValue(Integer.parseInt(propertyValue.substring(0,
							propertyValue.length() - 2)));
				} else if (propertyName.equalsIgnoreCase("height")) {
					// e.g., 80px
					cstyle.height_ = Utils.getScaledValue(Integer.parseInt(propertyValue.substring(0,
							propertyValue.length() - 2)));
				} else if (propertyName.equalsIgnoreCase("background-color")) {
					// e.g.,#00ff00
					String colorstr = null;
					colorstr = getValidColorString(propertyValue);
					cstyle.bgColor_ = Integer.parseInt(colorstr, 16);
					if (cstyle.bgColor_ != 0){
						cstyle.bgColor_ |= 0xFF000000;
					}
				} else if (propertyName.equalsIgnoreCase("background-image")) {
					// e.g.,url(/i/eg_bg_03.gif)
					cstyle.bgImageUrl_ = propertyValue.substring(4, propertyValue.length() - 1);
				} else if (propertyName.equalsIgnoreCase("color")) {
					// e.g.,#00ff00
					String colorstr = null;
					colorstr = getValidColorString(propertyValue);
					cstyle.fgColor_ = Integer.parseInt(colorstr, 16);
					cstyle.fgColor_ |= 0xFF000000;
				} else if (propertyName.equalsIgnoreCase("border")) {
					// e.g., 1px #00ff00 solid
					int widthIndex = 0;
					int colorIndex = 1;
					int[] properties = getBorderProperty(propertyValue);
					if (properties == null || properties.length != 2) {
						continue;
					}
					cstyle.borderWidth_ = properties[widthIndex];
					cstyle.borderColor_ = properties[colorIndex];
				} else if (propertyName.equalsIgnoreCase("border-left")) {
					// e.g., 1px #00ff00 solid
					int widthIndex = 0;
					int colorIndex = 1;
					int[] properties = getBorderProperty(propertyValue);
					if (properties == null || properties.length != 2) {
						continue;
					}
					initBorderWidth(cstyle);
					setBorderWidth(cstyle, properties[widthIndex], BORDER_LEFT);
					initBorderColor(cstyle);
					setBorderColor(cstyle, properties[colorIndex], BORDER_LEFT);
				} else if (propertyName.equalsIgnoreCase("border-top")) {
					// e.g., 1px #00ff00 solid
					int widthIndex = 0;
					int colorIndex = 1;
					int[] properties = getBorderProperty(propertyValue);
					if (properties == null || properties.length != 2) {
						continue;
					}
					initBorderWidth(cstyle);
					setBorderWidth(cstyle, properties[widthIndex], BORDER_TOP);
					initBorderColor(cstyle);
					setBorderColor(cstyle, properties[colorIndex], BORDER_TOP);
				} else if (propertyName.equalsIgnoreCase("border-right")) {
					// e.g., 1px #00ff00 solid
					int widthIndex = 0;
					int colorIndex = 1;
					int[] properties = getBorderProperty(propertyValue);
					if (properties == null || properties.length != 2) {
						continue;
					}
					initBorderWidth(cstyle);
					setBorderWidth(cstyle, properties[widthIndex], BORDER_RIGHT);
					initBorderColor(cstyle);
					setBorderColor(cstyle, properties[colorIndex], BORDER_RIGHT);
				} else if (propertyName.equalsIgnoreCase("border-bottom")) {
					// e.g., 1px #00ff00 solid
					int widthIndex = 0;
					int colorIndex = 1;
					int[] properties = getBorderProperty(propertyValue);
					if (properties == null || properties.length != 2) {
						continue;
					}
					initBorderWidth(cstyle);
					setBorderWidth(cstyle, properties[widthIndex], BORDER_BOTTOM);
					initBorderColor(cstyle);
					setBorderColor(cstyle, properties[colorIndex], BORDER_BOTTOM);
				} else if (propertyName.equalsIgnoreCase("font-family")) {
					cstyle.fontFamily_ = propertyValue;
				} else if (propertyName.equalsIgnoreCase("font-size")) {
					// e.g., 12px
					cstyle.fontSize_ = Utils.getScaledValue(Integer.parseInt(propertyValue.substring(0,
							propertyValue.length() - 2)));
				} else if (propertyName.equalsIgnoreCase("font-weight")) {
					cstyle.fontWeight_ = propertyValue;
				} else if (propertyName.equalsIgnoreCase("text-align")) {
					// e.g., left/right/center
					cstyle.textAlign_ = propertyValue;
				} else if (propertyName.equalsIgnoreCase("display")) {
					// e.g., none/block
					cstyle.display_ = propertyValue;
				} else if (propertyName.equalsIgnoreCase("left")) {
					// e.g., 4px
					cstyle.left_ = Integer.parseInt(propertyValue.substring(0, propertyValue.length() - 2));
				} else if (propertyName.equalsIgnoreCase("top")) {
					// e.g., 4px
					cstyle.top_ = Integer.parseInt(propertyValue.substring(0, propertyValue.length() - 2));
				} else if (propertyName.equalsIgnoreCase("right")) {
					// e.g., 4px
					cstyle.right_ = Integer.parseInt(propertyValue.substring(0, propertyValue.length() - 2));
				} else if (propertyName.equalsIgnoreCase("bottom")) {
					// e.g., 4px
					cstyle.bottom_ = Integer.parseInt(propertyValue.substring(0, propertyValue.length() - 2));
				} else if (propertyName.equalsIgnoreCase("strikethrough")) {
					// e.g., 4px
					cstyle.strikethrough_ = Integer.parseInt(propertyValue.substring(0, propertyValue.length() - 2));
				}
			} catch (Exception e) {
				continue;
			}
		}

		return cstyle;
	}

	private static int[] getBorderProperty(String propertyValue) throws Exception {
		int width;
		int color;
		int blankIndex = propertyValue.indexOf(' ');
		if (blankIndex == -1) {
			return null;
		}
		width = Integer.parseInt(propertyValue.substring(0, blankIndex - 2));

		propertyValue = propertyValue.substring(blankIndex + 1).trim();
		blankIndex = propertyValue.indexOf(' ');
		if (blankIndex == -1) {
			return null;
		}

		String colorstr = null;
		colorstr = getValidColorString(propertyValue.substring(0, blankIndex));
		color = Integer.parseInt(colorstr, 16);
		color |= 0xFF000000;

		return new int[] { width, color };
	}

	/**
	 * @param cstyle
	 * @param color
	 * @param dir
	 */
	private static void setBorderColor(CssStyle cstyle, int color, int dir) {
		try {
			cstyle.borderColors_[dir] = color;
		} catch (Exception e) {
		}
	}

	/**
	 * @param cstyle
	 */
	private static void initBorderColor(CssStyle cstyle) {
		if (cstyle.borderColors_ == null) {
			cstyle.borderColors_ = new int[4];
		}
	}

	/**
	 * @param cstyle
	 * @param width
	 * @param dir
	 */
	private static void setBorderWidth(CssStyle cstyle, int width, int dir) {
		try {
			cstyle.borderWidths_[dir] = width;
		} catch (Exception e) {
		}
	}

	/**
	 * @param cstyle
	 */
	private static void initBorderWidth(CssStyle cstyle) {
		if (cstyle.borderWidths_ == null) {
			cstyle.borderWidths_ = new int[4];
			cstyle.borderWidths_[BORDER_LEFT] = -1;
			cstyle.borderWidths_[BORDER_TOP] = -1;
			cstyle.borderWidths_[BORDER_RIGHT] = -1;
			cstyle.borderWidths_[BORDER_BOTTOM] = -1;
		}
	}

	/**
	 * The valid color string is a 6 bit hex number. e.g., FFFFFF.
	 * 
	 * @param srcColorstr
	 * @return
	 */
	private static final String getValidColorString(final String srcColorstr) throws Exception {
		String colorstr = srcColorstr;
		if (colorstr.startsWith("#")) {
			colorstr = colorstr.substring(1);
		}
		if (colorstr.length() > 6) {
			int end = colorstr.length();
			int start = end - 6;
			colorstr = colorstr.substring(start, end);
		}
		return colorstr;
	}

	/**
	 * Unite two styles on their inheritances.
	 * 
	 * @param superStyle
	 * @param subStyle
	 * @return
	 */
	static final CssStyle uniteStyle(CssStyle superStyle, CssStyle subStyle) {
		if (superStyle == null && subStyle == null) {
			return null;
		} else if (superStyle != null && subStyle != null) {
			CssStyle neoStyle = copy(superStyle);
			// font size
			if (subStyle.fontSize_ != -1) {
				neoStyle.fontSize_ = subStyle.fontSize_;
			}
			// font family
			if (subStyle.fontFamily_ != null) {
				neoStyle.fontFamily_ = subStyle.fontFamily_;
			}
			// font weight
			if (subStyle.fontWeight_ != null) {
				neoStyle.fontWeight_ = subStyle.fontWeight_;
			}
			// text align
			if (subStyle.textAlign_ != null) {
				neoStyle.textAlign_ = subStyle.textAlign_;
			}
			// font color.
			if (subStyle.fgColor_ != 0) {
				neoStyle.fgColor_ = subStyle.fgColor_;
			}
			// background color.
			if (subStyle.bgColor_ != 0) {
				neoStyle.bgColor_ = subStyle.bgColor_;
			}
			// top
			if (subStyle.top_ != Integer.MIN_VALUE) {
				neoStyle.top_ = subStyle.top_;
			}
			// bottom
			if (subStyle.bottom_ != Integer.MIN_VALUE) {
				neoStyle.bottom_ = subStyle.bottom_;
			}
			// left
			if (subStyle.left_ != Integer.MIN_VALUE) {
				neoStyle.left_ = subStyle.left_;
			}
			// right
			if (subStyle.right_ != Integer.MIN_VALUE) {
				neoStyle.right_ = subStyle.right_;
			}
			// width
			if (subStyle.width_ > 0) {
				neoStyle.width_ = subStyle.width_;
			}
			// height
			if (subStyle.height_ > 0) {
				neoStyle.height_ = subStyle.height_;
			}
			// background image
			if (subStyle.bgImageUrl_ != null) {
				neoStyle.bgImageUrl_ = subStyle.bgImageUrl_;
			}
			// border color
			if (subStyle.borderColor_ != 0) {
				neoStyle.borderColor_ = subStyle.borderColor_;
			}
			// border width
			if (subStyle.borderWidth_ > 0) {
				neoStyle.borderWidth_ = subStyle.borderWidth_;
			}
			// border color
			if (subStyle.borderColors_ != null) {
				neoStyle.borderColors_ = subStyle.borderColors_;
			}
			// border width
			if (subStyle.borderWidths_ != null) {
				neoStyle.borderWidths_ = subStyle.borderWidths_;
			}
			// display
			if (subStyle.display_ != null) {
				neoStyle.display_ = subStyle.display_;
			}

			return neoStyle;
		} else if (superStyle == null) {
			return subStyle;
		} else if (subStyle == null) {
			return superStyle;
		}
		return null;
	}

	public static final CssStyle copy(CssStyle srcStyle) {
		if (null == srcStyle)
			return null;
		CssStyle copyStyle = new CssStyle();
		copyStyle.fgColor_ = srcStyle.fgColor_;
		copyStyle.borderWidth_ = srcStyle.borderWidth_;
		copyStyle.borderColor_ = srcStyle.borderColor_;
		copyStyle.borderWidths_ = srcStyle.borderWidths_;
		copyStyle.borderColors_ = srcStyle.borderColors_;
		copyStyle.fontSize_ = srcStyle.fontSize_;
		copyStyle.fontFamily_ = srcStyle.fontFamily_;
		return copyStyle;
	}

}
